﻿
using System;

class XStreamParser
{
    private TransportState _transportState;
    public const int HeadLength = 4;
    private int _bufferOffset = 0;
    private byte[] _headBuffer = new byte[HeadLength];
    private int _pkgLength;
    private byte[] _buffer;

    //循环强引用，记得释放
    public XSocketClient socketClient;

    internal void ProcessBytes(byte[] bytes, int offset, int limit)
    {
        if (limit == 0) return;
        if (_transportState == TransportState.ReadHead)
        {
            ReadHead(bytes, offset, limit);
        }
        else if (_transportState == TransportState.ReadBody)
        {
            ReadBody(bytes, offset, limit);
        }
    }

    private void ReadHead(byte[] bytes, int offset, int limit)
    {
        int length = limit - offset;
        int headNum = HeadLength - _bufferOffset;

        //记住每次解析完一个协议包，_bufferOffset都会被归0

        if (length >= headNum)
        {
            //Write head buffer
            WriteBytes(bytes, offset, headNum, _bufferOffset, _headBuffer);
            //Get package length
            if (BitConverter.IsLittleEndian)
                Array.Reverse(_headBuffer);
            _pkgLength = BitConverter.ToInt32(_headBuffer, 0);

            //Init message buffer
            _buffer = new byte[HeadLength + _pkgLength];
            WriteBytes(_headBuffer, 0, HeadLength, _buffer);
            offset += headNum;
            _bufferOffset = HeadLength;
            _transportState = TransportState.ReadBody;

            if (offset <= limit)
            {
                ProcessBytes(bytes, offset, limit);
            }
        }
        else
        {
            //这次字节流长度比4个资源还短
            WriteBytes(bytes, offset, length, _bufferOffset, _headBuffer);
            _bufferOffset += length;
        }
    }

    private void ReadBody(byte[] bytes, int offset, int limit)
    {
        int length = _pkgLength + HeadLength - _bufferOffset;
        if ((offset + length) <= limit)
        {
            WriteBytes(bytes, offset, length, _bufferOffset, _buffer);
            offset += length;

            //Invoke the protocol api to handle the message
            var bodyData = new byte[_pkgLength];
            Array.Copy(_buffer, HeadLength, bodyData, 0, _pkgLength);

            //lock (_queueLock)
            //{
                socketClient.EnqueueStream(bodyData);
            //}

            _bufferOffset = 0;
            _pkgLength = 0;

            //if (_transportState != TransportState.Closed)
                _transportState = TransportState.ReadHead;
            if (offset < limit)
                ProcessBytes(bytes, offset, limit);
        }
        else
        {
            WriteBytes(bytes, offset, limit - offset, _bufferOffset, _buffer);
            _bufferOffset += limit - offset;
            _transportState = TransportState.ReadBody;
        }
    }

    private void WriteBytes(byte[] source, int start, int length, byte[] target)
    {
        WriteBytes(source, start, length, 0, target);
    }

    private void WriteBytes(byte[] source, int start, int length, int offset, byte[] target)
    {
        for (int i = 0; i < length; i++)
        {
            target[offset + i] = source[start + i];
        }
    }
}
